// UPCE.js - UPC-E 条码实现（压缩版 UPC，6 或 8 位）
// 参考：https://en.wikipedia.org/wiki/Universal_Product_Code#UPC-E

import Barcode from '../Barcode.js';
import encoder from './encoder.js';
import { checksum as upcChecksum } from './UPC.js'; // 复用 UPC-A 校验码逻辑

// UPC-E 扩展模板：将 6 位 UPC-E 映射为 10 位 UPC-A 中间部分
const EXPANSIONS = [
	'XX00000XXX', // 末位 0
	'XX10000XXX', // 末位 1
	'XX20000XXX', // 末位 2
	'XXX00000XX', // 末位 3
	'XXXX00000X', // 末位 4
	'XXXXX00005', // 末位 5
	'XXXXX00006', // 末位 6
	'XXXXX00007', // 末位 7
	'XXXXX00008', // 末位 8
	'XXXXX00009', // 末位 9
];

// 每个校验码和数制位对应的 L/E 编码模式（E = Even, O = Odd → 实际为 L/G）
// E 表示使用 L 编码表，O 表示使用 G 编码表（在 UPC-E 中，G 用于“奇偶反转”）
const PARITIES = [
	['EEEOOO', 'OOOEEE'], // check=0
	['EEOEOO', 'OOEOEE'],
	['EEOOEO', 'OOEEOE'],
	['EEOOOE', 'OOEEEO'],
	['EOEEOO', 'OEOOEE'],
	['EOOEEO', 'OEEOOE'],
	['EOOOEE', 'OEEEOO'],
	['EOEOEO', 'OEOEOE'],
	['EOEOOE', 'OEOEEO'],
	['EOOEOE', 'OEEOEO'],
];

/**
 * 将 UPC-E 的 6 位中间数字扩展为完整的 UPC-A 12 位码
 * @param {string} middleDigits - 6 位 UPC-E 数字
 * @param {string} numberSystem - 数制位（0 或 1）
 * @returns {string} 完整的 12 位 UPC-A 码
 */
function expandToUPCA(middleDigits, numberSystem) {
	const lastDigit = parseInt(middleDigits[5], 10);
	const expansion = EXPANSIONS[lastDigit];

	let upcAMiddle = '';
	let digitIndex = 0;

	for (let i = 0; i < expansion.length; i++) {
		if (expansion[i] === 'X') {
			upcAMiddle += middleDigits[digitIndex++];
		} else {
			upcAMiddle += expansion[i];
		}
	}

	const upcAWithoutCheck = numberSystem + upcAMiddle;
	const checkDigit = upcChecksum(upcAWithoutCheck);
	return upcAWithoutCheck + checkDigit;
}

export class UPCE extends Barcode {
	/**
	 * 构造函数
	 * @param {string} data - 6 位（无校验）或 8 位（含数制+校验）UPC-E
	 * @param {Object} options - 配置项
	 */
	constructor(data, options) {
		super(data, options);

		this.isValid = false;
		this.middleDigits = '';
		this.upcA = '';

		// 情况1：6位输入（自动补数制0，计算校验）
		if (/^[0-9]{6}$/.test(data)) {
			this.middleDigits = data;
			this.upcA = expandToUPCA(data, '0');
			this.text = options.text || this.upcA[0] + data + this.upcA[11];
			this.isValid = true;

			// 情况2：8位输入（第一位=数制，最后一位=校验）
		} else if (/^[01][0-9]{6}[0-9]$/.test(data)) {
			this.middleDigits = data.substring(1, 7); // 中间6位
			this.upcA = expandToUPCA(this.middleDigits, data[0]);

			// 验证校验码是否匹配
			if (this.upcA[11] === data[7]) {
				this.isValid = true;
			} else {
				// 校验失败
				this.isValid = false;
				return;
			}
		} else {
			// 格式错误
			this.isValid = false;
			return;
		}

		this.displayValue = options.displayValue !== false;

		// 字体大小限制
		this.fontSize = Math.min(options.fontSize, options.width * 10);

		// 守卫条高度：条码高度 + 半个字体高度 + 文字边距
		this.guardHeight =
			options.height + this.fontSize / 2 + (options.textMargin || 2);
	}

	/**
	 * 验证 UPC-E 是否有效
	 * @returns {boolean}
	 */
	valid() {
		return this.isValid;
	}

	/**
	 * 生成编码数据
	 * @returns {Object|Array} 扁平或分段结构
	 */
	encode() {
		return this.options.flat ? this.flatEncoding() : this.guardedEncoding();
	}

	/**
	 * 扁平编码（单一二进制流）
	 * @returns {Object}
	 */
	flatEncoding() {
		return {
			data: '101' + this.encodeMiddleDigits() + '010101',
			text: this.text,
		};
	}

	/**
	 * 分段编码（用于图形渲染）
	 * @returns {Array<{ data: string, text?: string, options?: Object }>}
	 */
	guardedEncoding() {
		const result = [];

		// 显示 UPC-A 数制位（左侧）
		if (this.displayValue) {
			result.push({
				data: '00000000',
				text: this.text[0],
				options: {
					textAlign: 'left',
					fontSize: this.fontSize,
				},
			});
		}

		// 左守卫条
		result.push({
			data: '101',
			options: { height: this.guardHeight },
		});

		// 中间6位（使用动态编码模式）
		result.push({
			data: this.encodeMiddleDigits(),
			text: this.text.substring(1, 7),
			options: { fontSize: this.fontSize },
		});

		// 右守卫条
		result.push({
			data: '010101',
			options: { height: this.guardHeight },
		});

		// 显示 UPC-A 校验位（右侧）
		if (this.displayValue) {
			result.push({
				data: '00000000',
				text: this.text[7],
				options: {
					textAlign: 'right',
					fontSize: this.fontSize,
				},
			});
		}

		return result;
	}

	/**
	 * 编码中间6位数字（根据数制和校验位选择 L/G 编码模式）
	 * @returns {string}
	 */
	encodeMiddleDigits() {
		const numberSystem = parseInt(this.upcA[0], 10);
		const checkDigit = parseInt(this.upcA[11], 10);
		const parity = PARITIES[checkDigit][numberSystem]; // 选择编码模式
		return encoder(this.middleDigits, parity);
	}
}


